package jmine.tec.web.wicket.pages.form;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

import jmine.tec.report.api.Report;
import jmine.tec.report.api.batch.ReportCreator;
import jmine.tec.web.wicket.component.command.button.ButtonCommand;
import jmine.tec.web.wicket.component.command.button.ButtonCommandsPanel;
import jmine.tec.web.wicket.component.command.button.SearchCommand;
import jmine.tec.web.wicket.component.report.ReportTablePanel;

import org.apache.wicket.PageParameters;
import org.apache.wicket.markup.html.WebMarkupContainer;
import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.markup.html.panel.EmptyPanel;
import org.apache.wicket.markup.html.panel.FeedbackPanel;
import org.apache.wicket.markup.html.panel.Panel;
import org.apache.wicket.model.CompoundPropertyModel;

/**
 * Abstração para páginas de relatório.
 * 
 * @author Gallardo
 * @param <T> tipo do parâmetro do relatório.
 */
public abstract class ReportPage<T extends Serializable> extends AbstractFormPage {

    private Form<T> form;

    /**
     * Construtor.
     */
    public ReportPage() {
        super();
    }

    /**
     * Construtor.
     * 
     * @param pageParameters {@link PageParameters}
     */
    public ReportPage(PageParameters pageParameters) {
        super(pageParameters);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    protected void onInitialize() {
        super.onInitialize();
        this.generateComponents();
    }
    
    /**
     * Inicializa o form.
     */
    private void generateComponents() {
        this.form = new Form<T>("mainForm") {
            @Override
            protected void onSubmit() {
                ReportPage.this.doRenderReport();
            }
        };
        this.add(new FeedbackPanel("feedback"));
        this.form.setModel(new CompoundPropertyModel<T>(this.createReportParameter()));
        this.addSearchFields(this.form);
        this.add(new EmptyPanel("report").setOutputMarkupId(true));
        this.form.add(new ButtonCommandsPanel("pageCommands", this.getPageCommands()));

        this.add(this.form);
    }

    /**
     * Rodado no submit do form.
     */
    protected final void doRenderReport() {
        ReportCreator<T> reportCreator = this.getReportCreator();
        List<Report> reports = reportCreator.createReports(this.form.getModelObject());
        Panel panel;
        if (reports.isEmpty()) {
            panel = new EmptyPanel("report");
        } else {
            Report report = reports.get(0);
            panel = this.createReportPanel("report", report);
        }
        panel.setOutputMarkupId(true);
        panel.setVisible(true);
        this.addOrReplace(panel);
    }

    /**
     * Adiciona campos ao form.
     * 
     * @deprecated use addSearchFields
     * @param formParam o form
     * @deprecated use {@link #addSearchFields(WebMarkupContainer)} instead
     */
    @Deprecated
    protected void addFields(Form<T> formParam) {
        // vazio, esse metodo vai ser removido
    }

    /**
     * Inclui os campos de pesquisa no container
     * 
     * @param container container
     */
    @SuppressWarnings("deprecation")
    protected void addSearchFields(WebMarkupContainer container) {
        // Hook
        this.addFields(this.form); // FIXME rafael.volpato: chamada existente somente para manter compatibilidade, vai ser removida
    }

    /**
     * Obtem a instância de reportCreator.
     * 
     * @return a instância de reportCreator.
     */
    protected abstract ReportCreator<T> getReportCreator();

    /**
     * Obtem a instância do reportParameter do relatório.
     * 
     * @return a instância do reportParameter do relatório.
     */
    protected abstract T createReportParameter();

    /**
     * @param id id
     * @param report {@link ReportBuilder}
     * @return {@link Panel}
     */
    protected Panel createReportPanel(String id, Report report) {
        return new ReportTablePanel(id, report);
    }

    /**
     * Retorna a lista de comandos que deve ser exibidos junto com a tabela de entidade encontradas.^M
     * 
     * @return lista de comandos que devem ser exibidos^M
     */
    protected List<ButtonCommand> getPageCommands() {
        List<ButtonCommand> commands = new ArrayList<ButtonCommand>();
        commands.add(new SearchCommand());
        return commands;
    }

}
